package de.bildung.koblenz.network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

import android.util.Log;

import de.bildung.koblenz.homeswitch.entities.Room;

public class SocketUtil {
	
	public static final byte SERVER_SWITCH_ON = 1;
	public static final byte SERVER_SWITCH_OFF = 2;
	public static final byte SERVER_GET_ROOMS = 3;
	public static final byte SERVER_GET_SOCKETS = 4;
	
	private Socket socket;
	
	public SocketUtil(String ip, String port) throws NumberFormatException, UnknownHostException, IOException {
		super();
		
		socket = new Socket(ip, Integer.parseInt(port));
	}
	
	public void close() throws IOException {
		socket.close();
	}
	
	public void turnSwitchOnOff(int id, boolean on) throws IOException {
		byte[] cmd = new byte[5];
		cmd[1] = (byte) (id >>>24);
		cmd[2] = (byte) (id >>>16);
		cmd[3] = (byte) (id >>>8);
		cmd[4] = (byte) (id);
		if (on)
			cmd[0] = SERVER_SWITCH_ON;
		else
			cmd[0] = SERVER_SWITCH_OFF;
		sendCommand(cmd, true);
	}
	
	public byte[] sendCommand(byte[] cmd, boolean skipWait) throws IOException {
		OutputStream out = socket.getOutputStream();
		InputStream in = socket.getInputStream();
		out.write(cmd);
		out.flush();
		if (skipWait) return null;
		byte[] result = new byte[1024];
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		Log.i("de.bildung", "bytes available: " + in.available());
		in.read(result);
		return result;
	}
	
	public List<de.bildung.koblenz.homeswitch.entities.Socket> getAllSwitches() throws IOException {
		List<de.bildung.koblenz.homeswitch.entities.Socket> result = new ArrayList<de.bildung.koblenz.homeswitch.entities.Socket>();
		byte[] response = null;
		byte[] cmd = new byte[] {SERVER_GET_SOCKETS};
		
		response = sendCommand(cmd, false);
		if (response != null) {
			int offset = 1;
			if (response[0] == SERVER_GET_SOCKETS) {
				int cnt = valueOf(response, offset);
				offset += 4;
				for (int i = 0; i < cnt; i++) {
					de.bildung.koblenz.homeswitch.entities.Socket socket = new de.bildung.koblenz.homeswitch.entities.Socket();
					socket.setId(valueOf(response, offset));
					offset += 4;
					// Die Werte werden noch nicht ausgewertet
					// byte on/off
					offset += 1;
					// int system code
					offset += 4;
					// byte unit code
					offset += 4;
					// int raum id
					socket.setRoomId(valueOf(response, offset));
					offset += 4;
					int nameLen = valueOf(response, offset);
					offset += 4;
					socket.setName(valueOf(response, offset, nameLen));
					offset += nameLen;
					result.add(socket);
				}
			}
		}
		return result;
	}
	
	public List<Room> getAllRooms() throws IOException {
		List<Room> result = new ArrayList<Room>();
		byte[] response = null;
		byte[] cmd = new byte[] {SERVER_GET_ROOMS};
		
		response = sendCommand(cmd, false);
		if (response != null) {
			int offset = 1;
			if (response[0] == SERVER_GET_ROOMS) {
				int cnt = valueOf(response, offset);
				offset += 4;
				for (int i = 0; i < cnt; i++) {
					Room room = new Room();
					room.setId(valueOf(response, offset));
					offset += 4;
					int nameLen = valueOf(response, offset);
					offset += 4;
					room.setName(valueOf(response, offset, nameLen));
					offset += nameLen;
					result.add(room);
				}
			}
		}
		
		return result;
	}
	
	private int valueOf(byte[] data, int offset) {
		ByteBuffer buffer = ByteBuffer.wrap(data, offset, 4);
		buffer.order(ByteOrder.BIG_ENDIAN);
		return buffer.getInt();
	}
	
	private String valueOf(byte[] data, int offset, int len) {
		return new String(data, offset, len);
	}

}
